package udpClient

import (
	"errors"
	"net"
	"sync"
	"time"

	"github.com/RuiGuangServer/logs"
)

type HandlerFunc func(data []byte, logger *logs.AsyncLogger, dataer *logs.AsyncLogger)

type UDPClient struct {
	ListenAddr string // 监听地址，格式如 ":30001"
	Handler    HandlerFunc
	conn       *net.UDPConn
	wg         sync.WaitGroup
	running    bool
	Reconnect  bool
}

func NewUDPClient(listenAddr string, handler HandlerFunc, reconnect bool) *UDPClient {
	return &UDPClient{
		ListenAddr: listenAddr,
		Handler:    handler,
		Reconnect:  reconnect,
	}
}

func (c *UDPClient) Start(logger *logs.AsyncLogger, dataer *logs.AsyncLogger) error {
	c.running = true
	c.wg.Add(1)

	go func() {
		defer c.wg.Done()

		for c.running {
			// 解析监听地址
			udpAddr, err := net.ResolveUDPAddr("udp", c.ListenAddr)
			if err != nil {
				logger.Error("ResolveUDPAddr error: %v", err)
				if !c.Reconnect {
					return
				}
				time.Sleep(5 * time.Second)
				continue
			}

			// 创建UDP监听
			conn, err := net.ListenUDP("udp", udpAddr)
			if err != nil {
				logger.Error("ListenUDP error: %v", err)
				if !c.Reconnect {
					return
				}
				time.Sleep(5 * time.Second)
				continue
			}
			c.conn = conn

			logger.Info("UDP client listening on %s", c.ListenAddr)

			// 接收数据循环
			buffer := make([]byte, 65535)
			for c.running {
				// 设置读取超时以便检查running状态
				_ = conn.SetReadDeadline(time.Now().Add(1 * time.Second))

				n, remoteAddr, err := conn.ReadFromUDP(buffer)
				if err != nil {
					var netErr net.Error
					if errors.As(err, &netErr) && netErr.Timeout() {
						continue // 超时是预期的
					}
					if c.running {
						logger.Error("UDP read error: %v", err)
					}
					break
				}

				data := make([]byte, n)
				copy(data, buffer[:n])
				logger.Debug("Received %d bytes from %s", n, remoteAddr)

				if c.Handler != nil {
					c.Handler(data, logger, dataer)
				}
			}

			_ = conn.Close()

			if !c.Reconnect {
				return
			}

			logger.Info("Reconnecting UDP client in 5 seconds...")
			time.Sleep(5 * time.Second)
		}
	}()

	return nil
}

func (c *UDPClient) Stop() {
	c.running = false
	if c.conn != nil {
		_ = c.conn.Close()
	}
	c.wg.Wait()
}
